diff --git a/frameworks/userver/Dockerfile b/frameworks/userver/Dockerfile index 3643a9323..d35c2585a 100644 --- a/frameworks/userver/Dockerfile +++ b/frameworks/userver/Dockerfile @@ -1,24 +1,19 @@ -FROM ghcr.io/userver-framework/ubuntu-24.04-userver-base AS builder +FROM ghcr.io/userver-framework/ubuntu-24.04-userver:v3.0 AS builder WORKDIR /src -RUN git clone https://github.com/userver-framework/userver.git && \ - cd userver && git checkout v3.0 - COPY userver_benchmark/ ./ RUN mkdir build && cd build && \ - cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=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++-17 -DCMAKE_C_COMPILER=clang-17 \ - -DUSERVER_LTO=0 .. && \ - make -j $(nproc) + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_FLAGS="-march=native" \ + -DCMAKE_C_FLAGS="-march=native" .. && \ + cmake --build . -j $(nproc) + FROM builder AS runner WORKDIR /app -COPY userver_configs/* ./ +COPY --from=builder /src/configs/config-vars.httparena.yaml ./configs/config_vars.yaml +COPY --from=builder /src/configs/static_config.yaml ./configs/ COPY --from=builder /src/build/userver_httparena ./ -EXPOSE 8080 -CMD ./userver_httparena -c ./static_config.yaml +EXPOSE 8080 8443 8081 +CMD ./userver_httparena -c ./configs/static_config.yaml diff --git a/frameworks/userver/meta.json b/frameworks/userver/meta.json index d6db5add1..d811c93ed 100644 --- a/frameworks/userver/meta.json +++ b/frameworks/userver/meta.json @@ -10,7 +10,13 @@ "baseline", "pipelined", "limited-conn", - "static" + "json", + "json-comp", + "upload", + "api-4", + "api-16", + "static", + "async-db" ], "maintainers": ["botanegg"] } diff --git a/frameworks/userver/userver_benchmark/.clang-format b/frameworks/userver/userver_benchmark/.clang-format index 276eaf0a6..3210ab4a2 100644 --- a/frameworks/userver/userver_benchmark/.clang-format +++ b/frameworks/userver/userver_benchmark/.clang-format @@ -1,3 +1,4 @@ BasedOnStyle: google DerivePointerAlignment: false IncludeBlocks: Preserve +ColumnLimit: 120 diff --git a/frameworks/userver/userver_benchmark/.gitignore b/frameworks/userver/userver_benchmark/.gitignore new file mode 100644 index 000000000..4945d8b8e --- /dev/null +++ b/frameworks/userver/userver_benchmark/.gitignore @@ -0,0 +1,18 @@ +__pycache__ +build*/ +compile_commands.json +.cache/ +.ccache/ +.idea/ +.vscode/ +!.vscode/c_cpp_properties.json +!.vscode/cmake-variants.yaml +!.vscode/README.md +.cores/ +cmake-build-* +Testing/ +.DS_Store +Makefile.local +CMakeUserPresets.json +configs/secure_data.json +third_party/ \ No newline at end of file diff --git a/frameworks/userver/userver_benchmark/CMakeLists.txt b/frameworks/userver/userver_benchmark/CMakeLists.txt index 1e9ff8b44..10236f936 100644 --- a/frameworks/userver/userver_benchmark/CMakeLists.txt +++ b/frameworks/userver/userver_benchmark/CMakeLists.txt @@ -1,17 +1,57 @@ -cmake_minimum_required(VERSION 3.12) +cmake_minimum_required(VERSION 3.12...3.31) project(userver_httparena CXX) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) -file(GLOB_RECURSE SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/controllers/*.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/common/*.cpp -) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +include(DownloadUserver) + +#boost context find problem hack +find_package(Boost CONFIG REQUIRED COMPONENTS context) -include(GNUInstallDirs) +find_package( + userver + COMPONENTS core # + postgresql + QUIET +) +if (NOT userver_FOUND) + # Tries TRY_DIR first, falls back to downloading userver from GitHub using CPM. + download_userver(TRY_DIR third_party/userver) +endif () -add_subdirectory(userver) userver_setup_environment() -add_executable(${PROJECT_NAME} ${SOURCES} userver_httparena.cpp) -target_link_libraries(${PROJECT_NAME} PRIVATE userver-core userver-postgresql userver-llhttp) +# Common sources +include_directories(src) + +add_library( + ${PROJECT_NAME}_objs OBJECT + src/handlers/baseline11/handler.hpp + src/handlers/baseline11/handler.cpp + src/handlers/baseline2/handler.hpp + src/handlers/baseline2/handler.cpp + src/handlers/json/handler.hpp + src/handlers/json/handler.cpp + src/handlers/plaintext/handler.hpp + src/handlers/plaintext/handler.cpp + src/handlers/upload/handler.hpp + src/handlers/upload/handler.cpp + src/handlers/async_db/handler.hpp + src/handlers/async_db/handler.cpp + src/dataset_provider.hpp + src/dataset_provider.cpp + src/middlewares/compression.hpp + src/middlewares/compression.cpp + src/middlewares/compression_pipeline_builder.hpp +) +target_link_libraries( + ${PROJECT_NAME}_objs + PUBLIC userver::core # + userver::postgresql +) + +# The Service +add_executable(${PROJECT_NAME} src/main.cpp) +target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_objs) diff --git a/frameworks/userver/userver_benchmark/CMakePresets.json b/frameworks/userver/userver_benchmark/CMakePresets.json new file mode 100644 index 000000000..f91b7a6e3 --- /dev/null +++ b/frameworks/userver/userver_benchmark/CMakePresets.json @@ -0,0 +1,44 @@ +{ + "version": 2, + "cmakeMinimumRequired": { + "major": 3, + "minor": 20, + "patch": 0 + }, + "configurePresets": [ + { + "name": "debug", + "displayName": "Debug", + "description": "Fully featured Debug build", + "inherits": [ + "common-flags" + ], + "binaryDir": "${sourceDir}/build-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "USERVER_SANITIZE": "ub" + } + }, + { + "name": "release", + "displayName": "Release", + "description": "Fully featured Release build", + "inherits": [ + "common-flags" + ], + "binaryDir": "${sourceDir}/build-release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "common-flags", + "hidden": true, + "generator": "Ninja", + "cacheVariables": { + "USERVER_FEATURE_POSTGRESQL": "ON", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + } + ] +} \ No newline at end of file diff --git a/frameworks/userver/userver_benchmark/README.md b/frameworks/userver/userver_benchmark/README.md new file mode 100644 index 000000000..afa6bf7db --- /dev/null +++ b/frameworks/userver/userver_benchmark/README.md @@ -0,0 +1,37 @@ +# userver_httparena + +Template of a C++ service that uses [userver framework](https://github.com/userver-framework/userver). + + +## Download and Build + +To create your own userver-based service follow the following steps: + +1. Press the "Use this template button" at the top right of this GitHub page +2. Clone the service `git clone your-service-repo && cd your-service-repo && git submodule update --init` +3. Give a proper name to your service and replace all the occurrences of "userver_httparena" string with that name +4. Feel free to tweak, adjust or fully rewrite the source code of your service. + + +## Makefile + +`PRESET` is either `debug`, `release`, or if you've added custom presets in `CMakeUserPresets.json`, it +can also be `debug-custom`, `release-custom`. + +* `make cmake-PRESET` - run cmake configure, update cmake options and source file lists +* `make build-PRESET` - build the service +* `make test-PRESET` - build the service and run all tests +* `make start-PRESET` - build the service, start it in testsuite environment and leave it running +* `make install-PRESET` - build the service and install it in directory set in environment `PREFIX` +* `make` or `make all` - build and run all tests in `debug` and `release` modes +* `make format` - reformat all C++ and Python sources +* `make dist-clean` - clean build files and cmake cache +* `make docker-COMMAND` - run `make COMMAND` in docker environment +* `make docker-clean-data` - stop docker containers + + +## License + +The original template is distributed under the [Apache-2.0 License](https://github.com/userver-framework/userver/blob/develop/LICENSE) +and [CLA](https://github.com/userver-framework/userver/blob/develop/CONTRIBUTING.md). Services based on the template may change +the license and CLA. \ No newline at end of file diff --git a/frameworks/userver/userver_benchmark/cmake/DownloadUserver.cmake b/frameworks/userver/userver_benchmark/cmake/DownloadUserver.cmake new file mode 100644 index 000000000..4c945366a --- /dev/null +++ b/frameworks/userver/userver_benchmark/cmake/DownloadUserver.cmake @@ -0,0 +1,42 @@ +include_guard(GLOBAL) + +function(download_userver) + set(OPTIONS) + set(ONE_VALUE_ARGS TRY_DIR VERSION GIT_TAG) + set(MULTI_VALUE_ARGS) + cmake_parse_arguments(ARG "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN}) + + if(ARG_TRY_DIR) + get_filename_component(ARG_TRY_DIR "${ARG_TRY_DIR}" REALPATH) + if(EXISTS "${ARG_TRY_DIR}") + message(STATUS "Using userver from ${ARG_TRY_DIR}") + add_subdirectory("${ARG_TRY_DIR}" third_party/userver) + return() + endif() + endif() + + # CMP0077 and CMP0126 are required for correct option forwarding. + cmake_minimum_required(VERSION 3.21) + include(get_cpm) + + if(NOT DEFINED ARG_VERSION AND NOT DEFINED ARG_GIT_TAG) + set(ARG_GIT_TAG develop) + endif() + + if(NOT DEFINED CPM_USE_NAMED_CACHE_DIRECTORIES) + set(CPM_USE_NAMED_CACHE_DIRECTORIES ON) + endif() + + cpmaddpackage( + NAME + userver + GITHUB_REPOSITORY + userver-framework/userver + VERSION + ${ARG_VERSION} + GIT_TAG + ${ARG_GIT_TAG} + GIT_SHALLOW TRUE + ${ARG_UNPARSED_ARGUMENTS} + ) +endfunction() \ No newline at end of file diff --git a/frameworks/userver/userver_benchmark/cmake/get_cpm.cmake b/frameworks/userver/userver_benchmark/cmake/get_cpm.cmake new file mode 100644 index 000000000..ee8ff15e5 --- /dev/null +++ b/frameworks/userver/userver_benchmark/cmake/get_cpm.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +# +# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors + +set(CPM_DOWNLOAD_VERSION 0.42.1) +set(CPM_HASH_SUM "f3a6dcc6a04ce9e7f51a127307fa4f699fb2bade357a8eb4c5b45df76e1dc6a5") + +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +endif() + +# Expand relative path. This is important if the provided path contains a tilde (~) +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) + +file(DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} +) + +include(${CPM_DOWNLOAD_LOCATION}) diff --git a/frameworks/userver/userver_benchmark/common/db_helpers.cpp b/frameworks/userver/userver_benchmark/common/db_helpers.cpp deleted file mode 100644 index 3627889ab..000000000 --- a/frameworks/userver/userver_benchmark/common/db_helpers.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "db_helpers.hpp" - -#include -#include - -#include - -namespace userver_httparena::db_helpers { - -namespace { - -int ParseFromQueryVal(std::string_view query_val) { - if (query_val.empty()) { - return 1; - } - - int parse_result{}; - const auto [ptr, err] = std::from_chars( - query_val.data(), query_val.data() + query_val.size(), parse_result); - if (err != std::errc{} || ptr != query_val.data() + query_val.size()) { - return 1; - } - - return std::min(500, std::max(1, parse_result)); -} - -} // namespace - -userver::storages::postgres::Query CreateNonLoggingQuery( - std::string statement) { - return userver::storages::postgres::Query{ - 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); -} - -int GenerateRandomValue() { - return userver::utils::RandRange(1, kMaxWorldRows + 1); -} - -int ParseParamFromQuery(const userver::server::http::HttpRequest& request, - const std::string& name) { - const auto& arg_str = request.GetArg(name); - return ParseFromQueryVal(arg_str); -} - -int ParseParamFromQuery(std::string_view url, std::string_view name) { - auto pos = url.find(name); - if (pos == std::string_view::npos) { - return 1; - } - pos += name.size() + 1; // +1 for '=' - - std::size_t len = 0; - while (pos + len < url.size() && std::isdigit(url[pos + len])) { - ++len; - } - - return ParseFromQueryVal(url.substr(pos, len)); -} - -DatabasePoolSemaphore::DatabasePoolSemaphore(std::size_t initial_count) - : semaphore_{initial_count} {} - -userver::engine::SemaphoreLock DatabasePoolSemaphore::Acquire() const { - return userver::engine::SemaphoreLock{semaphore_}; -} - -} // namespace userver_httparena::db_helpers diff --git a/frameworks/userver/userver_benchmark/common/db_helpers.hpp b/frameworks/userver/userver_benchmark/common/db_helpers.hpp deleted file mode 100644 index eac4cdb80..000000000 --- a/frameworks/userver/userver_benchmark/common/db_helpers.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace userver_httparena::db_helpers { - -userver::storages::postgres::Query CreateNonLoggingQuery(std::string statement); - -constexpr int kMaxWorldRows = 10000; - -const userver::storages::postgres::Query kSelectRowQuery = - CreateNonLoggingQuery("SELECT id, randomNumber FROM World WHERE id = $1"); - -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 { - int id; - int random_number; -}; - -void WriteToStream(const WorldTableRow& row, - userver::formats::json::StringBuilder& sb); - -int GenerateRandomId(); -int GenerateRandomValue(); - -int ParseParamFromQuery(const userver::server::http::HttpRequest& request, - const std::string& name); - -int ParseParamFromQuery(std::string_view url, std::string_view name); - -class DatabasePoolSemaphore final { - public: - explicit DatabasePoolSemaphore(std::size_t initial_count); - - userver::engine::SemaphoreLock Acquire() const; - - private: - mutable userver::engine::Semaphore semaphore_; -}; - -} // namespace userver_httparena::db_helpers diff --git a/frameworks/userver/userver_benchmark/configs/config-vars.httparena.yaml b/frameworks/userver/userver_benchmark/configs/config-vars.httparena.yaml new file mode 100644 index 000000000..132762562 --- /dev/null +++ b/frameworks/userver/userver_benchmark/configs/config-vars.httparena.yaml @@ -0,0 +1,9 @@ +server-port: 8080 +tls-port: 8443 +json-tls-port: 8081 +tls-cert: /certs/server.crt +tls-key: /certs/server.key + +static-data-dir: /data/static + +dataset-path: /data/dataset.json diff --git a/frameworks/userver/userver_benchmark/configs/config_vars.yaml b/frameworks/userver/userver_benchmark/configs/config_vars.yaml new file mode 100644 index 000000000..0cda48c2d --- /dev/null +++ b/frameworks/userver/userver_benchmark/configs/config_vars.yaml @@ -0,0 +1,9 @@ +server-port: 8080 +tls-port: 8443 +json-tls-port: 8081 +tls-cert: ../../../certs/server.crt +tls-key: ../../../certs/server.key + +static-data-dir: ../../../data/static + +dataset-path: ../../../data/dataset.json diff --git a/frameworks/userver/userver_configs/static_config.yaml b/frameworks/userver/userver_benchmark/configs/static_config.yaml similarity index 57% rename from frameworks/userver/userver_configs/static_config.yaml rename to frameworks/userver/userver_benchmark/configs/static_config.yaml index 95a5bca6f..ef77dd03a 100644 --- a/frameworks/userver/userver_configs/static_config.yaml +++ b/frameworks/userver/userver_benchmark/configs/static_config.yaml @@ -1,4 +1,5 @@ # yaml +config_vars: configs/config_vars.yaml components_manager: event_thread_pool: threads: 8 @@ -8,7 +9,6 @@ components_manager: stack_size: 66560 # 64Kb for coroutine stack task_processors: # Task processor is an executor for coroutine tasks - 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: 64 @@ -22,11 +22,25 @@ components_manager: components: # Configuring components that were registered via component_list server: - listener: # configuring the main listening socket... - port: 8080 # ...to listen on this port and... - task_processor: main-task-processor # ...process incoming requests on this task processor. - #handler-defaults: - # set_tracing_headers: false + listener: + # TLS ports are disabled until upstream userver supports + # per-port TLS config (listener_impl.cpp: always uses ports[0]) + ports: + - port: $server-port +# PORTS for http2 and tls benchmarks +# - port: $tls-port +# tls: +# cert: $tls-cert +# private-key: $tls-key +# - port: $json-tls-port +# tls: +# cert: $tls-cert +# private-key: $tls-key + task_processor: main-task-processor + handler-defaults: + set_tracing_headers: false + max_request_size: 26214400 + max_headers_size: 65535 server-name: userver logging: fs-task-processor: fs-task-processor @@ -46,18 +60,13 @@ components_manager: testsuite-support: - secdist: {} # Component that stores configuration of hosts and passwords - default-secdist-provider: - config: /app/secure_data.json # Values are supposed to be stored in this file - missing-ok: false - noop-tracing-manager: tracing-manager-locator: component-name: noop-tracing-manager fs-cache-static: - dir: /data/static/ - update-period: 60s + dir: $static-data-dir + update-period: 0 # files are immutable during benchmark fs-task-processor: fs-task-processor handler-static: @@ -79,23 +88,45 @@ components_manager: task_processor: main-task-processor json-handler: - path: /json + path: /json/{count} + method: GET + decompress_request: false + task_processor: main-task-processor + middlewares: + pipeline-builder: compression-pipeline-builder + + upload-handler: + path: /upload + method: POST + decompress_request: false + task_processor: main-task-processor + + async-db-handler: + path: /async-db method: GET decompress_request: false task_processor: main-task-processor + baseline2-handler: + path: /baseline2 + method: GET + decompress_request: false + task_processor: main-task-processor + + compression-pipeline-builder: + + dataset-provider: + dataset-path: $dataset-path + hello-world-db: - dbalias: hello_world + dbconnection#env: DATABASE_URL # HttpArena benchmark env + dbconnection#fallback: postgresql://bench:bench@localhost:5432/benchmark?sslmode=disable # local dev + min_pool_size: 64 + max_pool_size#env: DATABASE_MAX_CONN # HttpArena benchmark env (set to 256) + max_pool_size#fallback: 256 # local dev + # min == max: pre-warm all connections at startup for benchmark blocking_task_processor: fs-task-processor - min_pool_size: 80 - max_pool_size: 260 max_queue_size: 512 connecting_limit: 15 ignore_unused_query_params: true connlimit_mode: manual - - single-query-handler: - path: /single-query - method: GET - decompress_request: false - task_processor: main-task-processor diff --git a/frameworks/userver/userver_benchmark/controllers/baseline11/handler.cpp b/frameworks/userver/userver_benchmark/controllers/baseline11/handler.cpp deleted file mode 100644 index 1c6aa781e..000000000 --- a/frameworks/userver/userver_benchmark/controllers/baseline11/handler.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "handler.hpp" - -#include - -namespace userver_httparena::baseline11 { - -const std::string kContentTypeTextPlain{"text/plain"}; - -std::string Handler::HandleRequestThrow(const userver::server::http::HttpRequest& request, userver::server::request::RequestContext&) const -{ - const auto & a = request.GetArg("a"); - const auto & b = request.GetArg("b"); - std::string body; - if (request.GetMethod() == userver::server::http::HttpMethod::kPost) { - body = request.RequestBody(); - } - request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, kContentTypeTextPlain); - return GetResponse(a, b, body); -} - -std::string Handler::GetResponse(const std::string& a, const std::string& b, const std::string& body) -{ - int sum = std::stoi(a) + std::stoi(b); - if (!body.empty()) { - sum += std::stoi(body); - } - return std::to_string(sum); -} - -} // namespace userver_httparena::baseline11 diff --git a/frameworks/userver/userver_benchmark/controllers/baseline11/handler.hpp b/frameworks/userver/userver_benchmark/controllers/baseline11/handler.hpp deleted file mode 100644 index a8b14f2b2..000000000 --- a/frameworks/userver/userver_benchmark/controllers/baseline11/handler.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -namespace userver_httparena::baseline11 { - -class Handler final - : public userver::server::handlers::HttpHandlerBase -{ -public: - static constexpr std::string_view kName = "baseline11-handler"; - - using HttpHandlerBase::HttpHandlerBase; - - std::string HandleRequestThrow(const userver::server::http::HttpRequest& request, userver::server::request::RequestContext&) const final; - - static std::string GetResponse(const std::string& a, const std::string& b, const std::string& body); -}; - -} // namespace userver_httparena::baseline11 diff --git a/frameworks/userver/userver_benchmark/controllers/json/handler.cpp b/frameworks/userver/userver_benchmark/controllers/json/handler.cpp deleted file mode 100644 index e21c84adc..000000000 --- a/frameworks/userver/userver_benchmark/controllers/json/handler.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "handler.hpp" - -#include -#include - -namespace userver_httparena::json { - -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(); -} - -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_httparena::json diff --git a/frameworks/userver/userver_benchmark/controllers/json/handler.hpp b/frameworks/userver/userver_benchmark/controllers/json/handler.hpp deleted file mode 100644 index c4256192b..000000000 --- a/frameworks/userver/userver_benchmark/controllers/json/handler.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -namespace userver_httparena::json { - -class Handler final - : public userver::server::handlers::HttpHandlerBase -{ -public: - static constexpr std::string_view kName = "json-handler"; - - using HttpHandlerBase::HttpHandlerBase; - - std::string HandleRequestThrow(const userver::server::http::HttpRequest&, userver::server::request::RequestContext&) const final; - - static std::string GetResponse(); -}; - -} // namespace userver_httparena::json diff --git a/frameworks/userver/userver_benchmark/controllers/plaintext/handler.cpp b/frameworks/userver/userver_benchmark/controllers/plaintext/handler.cpp deleted file mode 100644 index 1a69b6c3d..000000000 --- a/frameworks/userver/userver_benchmark/controllers/plaintext/handler.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "handler.hpp" - -#include - -namespace userver_httparena::plaintext { - -const std::string kContentTypeTextPlain{"text/plain"}; - -std::string Handler::HandleRequestThrow(const userver::server::http::HttpRequest& request, userver::server::request::RequestContext&) const -{ - request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, kContentTypeTextPlain); - return GetResponse(); -} - -std::string Handler::GetResponse() -{ - return "ok"; -} - -} // namespace userver_httparena::plaintext diff --git a/frameworks/userver/userver_benchmark/controllers/plaintext/handler.hpp b/frameworks/userver/userver_benchmark/controllers/plaintext/handler.hpp deleted file mode 100644 index 23d7acaf8..000000000 --- a/frameworks/userver/userver_benchmark/controllers/plaintext/handler.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -namespace userver_httparena::plaintext { - -class Handler final - : public userver::server::handlers::HttpHandlerBase -{ -public: - static constexpr std::string_view kName = "plaintext-handler"; - - using HttpHandlerBase::HttpHandlerBase; - - std::string HandleRequestThrow(const userver::server::http::HttpRequest& request, userver::server::request::RequestContext&) const final; - - static std::string GetResponse(); -}; - -} // namespace userver_httparena::plaintext diff --git a/frameworks/userver/userver_benchmark/controllers/single_query/handler.cpp b/frameworks/userver/userver_benchmark/controllers/single_query/handler.cpp deleted file mode 100644 index 3f41ec1e4..000000000 --- a/frameworks/userver/userver_benchmark/controllers/single_query/handler.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "handler.hpp" - -#include -#include -#include - -namespace userver_httparena::single_query { - -namespace { - -constexpr std::size_t kBestConcurrencyWildGuess = 256; - -} - -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context) - : userver::server::handlers::HttpHandlerBase{config, context}, - pg_{context - .FindComponent( - db_helpers::kDbComponentName) - .GetCluster()}, - semaphore_{kBestConcurrencyWildGuess} { } - -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(); -} - -std::string Handler::GetResponse() const -{ - const auto row = [this] { - const auto lock = semaphore_.Acquire(); - return pg_ - ->Execute(db_helpers::kClusterHostType, db_helpers::kDefaultPgCC, - db_helpers::kSelectRowQuery, db_helpers::GenerateRandomId()) - .AsSingleRow( - userver::storages::postgres::kRowTag); - }(); - - userver::formats::json::StringBuilder sb{}; - WriteToStream(row, sb); - return sb.GetString(); -} - -} // namespace userver_httparena::single_query diff --git a/frameworks/userver/userver_benchmark/controllers/single_query/handler.hpp b/frameworks/userver/userver_benchmark/controllers/single_query/handler.hpp deleted file mode 100644 index a741763ff..000000000 --- a/frameworks/userver/userver_benchmark/controllers/single_query/handler.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "../../common/db_helpers.hpp" - -#include - -#include - -namespace userver_httparena::single_query { - -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); - - std::string HandleRequestThrow(const userver::server::http::HttpRequest&, userver::server::request::RequestContext&) const final; - - std::string GetResponse() const; - -private: - const userver::storages::postgres::ClusterPtr pg_; - - db_helpers::DatabasePoolSemaphore semaphore_; -}; - -} // namespace userver_httparena::single_query diff --git a/frameworks/userver/userver_benchmark/src/dataset_provider.cpp b/frameworks/userver/userver_benchmark/src/dataset_provider.cpp new file mode 100644 index 000000000..c08c7594d --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/dataset_provider.cpp @@ -0,0 +1,50 @@ +#include "dataset_provider.hpp" + +#include +#include +#include +#include +#include + +namespace userver_httparena { +namespace { +Item ParseItem(const userver::formats::json::Value& item_json) { + Item item; + item.id = item_json["id"].As(); + item.name = item_json["name"].As(); + item.category = item_json["category"].As(); + item.price = item_json["price"].As(); + item.quantity = item_json["quantity"].As(); + item.active = item_json["active"].As(); + for (const auto& tag : item_json["tags"]) { + item.tags.push_back(tag.As()); + } + item.rating.score = item_json["rating"]["score"].As(); + item.rating.count = item_json["rating"]["count"].As(); + return item; +} +} // namespace + +DatasetProvider::DatasetProvider(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : ComponentBase(config, context) { + const auto path = config["dataset-path"].As(); + const auto doc = userver::formats::json::blocking::FromFile(path); + for (const auto& item_json : doc) { + items_.push_back(ParseItem(item_json)); + } +} + +userver::yaml_config::Schema DatasetProvider::GetStaticConfigSchema() { + return userver::yaml_config::MergeSchemas( + R"( +type: object +description: Dataset provider component +additionalProperties: false +properties: + dataset-path: + type: string + description: path to the JSON dataset file +)"); +} +} // namespace userver_httparena diff --git a/frameworks/userver/userver_benchmark/src/dataset_provider.hpp b/frameworks/userver/userver_benchmark/src/dataset_provider.hpp new file mode 100644 index 000000000..2ddb838f1 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/dataset_provider.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace userver_httparena { +struct Item { + int64_t id; + std::string name; + std::string category; + int64_t price; + int64_t quantity; + bool active; + std::vector tags; + + struct { + int64_t score; + int64_t count; + } rating; +}; + +class DatasetProvider final : public userver::components::ComponentBase { + public: + static constexpr std::string_view kName = "dataset-provider"; + + DatasetProvider(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context); + + static constexpr auto kConfigFileMode = userver::components::ConfigFileMode::kNotRequired; + + static userver::yaml_config::Schema GetStaticConfigSchema(); + + const std::vector& GetItems() const { return items_; } + + private: + std::vector items_; +}; +} // namespace userver_httparena diff --git a/frameworks/userver/userver_benchmark/src/handlers/async_db/handler.cpp b/frameworks/userver/userver_benchmark/src/handlers/async_db/handler.cpp new file mode 100644 index 000000000..2f00e6e68 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/async_db/handler.cpp @@ -0,0 +1,99 @@ +#include "handler.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace userver_httparena::async_db { +namespace { +struct ItemRow { + int64_t id; + std::string name; + std::string category; + int64_t price; + int64_t quantity; + bool active; + userver::formats::json::Value tags; + int64_t rating_score; + int64_t rating_count; +}; +} // namespace + +Handler::Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : HttpHandlerBase(config, context), + pg_{context.FindComponent("hello-world-db").GetCluster()} {} + +std::string Handler::HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const { + const auto& min_str = request.GetArg("min"); + const auto& max_str = request.GetArg("max"); + const auto& limit_str = request.GetArg("limit"); + + auto min = 10; + auto max = 50; + auto limit = 50; + if (!min_str.empty()) std::from_chars(min_str.data(), min_str.data() + min_str.size(), min); + if (!max_str.empty()) std::from_chars(max_str.data(), max_str.data() + max_str.size(), max); + if (!limit_str.empty()) std::from_chars(limit_str.data(), limit_str.data() + limit_str.size(), limit); + + // Matches + // https://www.http-arena.com/docs/test-profiles/h1/isolated/async-database/implementation/ + // kSlave falls back to master if no read replica is available + auto res = pg_->Execute(userver::storages::postgres::ClusterHostType::kSlave, + "SELECT id, name, category, price, quantity, active, tags, " + "rating_score, rating_count FROM items " + "WHERE price BETWEEN $1 AND $2 LIMIT $3", + min, max, limit); + + const auto rows = res.AsContainer >(userver::storages::postgres::kRowTag); + + userver::formats::json::StringBuilder sb; + { + userver::formats::json::StringBuilder::ObjectGuard root_guard(sb); + sb.Key("count"); + sb.WriteInt64(static_cast(rows.size())); + sb.Key("items"); + { + userver::formats::json::StringBuilder::ArrayGuard items_guard(sb); + for (const auto& row : rows) { + userver::formats::json::StringBuilder::ObjectGuard item_guard(sb); + sb.Key("id"); + sb.WriteInt64(row.id); + sb.Key("name"); + sb.WriteString(row.name); + sb.Key("category"); + sb.WriteString(row.category); + sb.Key("price"); + sb.WriteInt64(row.price); + sb.Key("quantity"); + sb.WriteInt64(row.quantity); + sb.Key("active"); + sb.WriteBool(row.active); + sb.Key("tags"); + sb.WriteValue(row.tags); + sb.Key("rating"); + { + userver::formats::json::StringBuilder::ObjectGuard rating_guard(sb); + sb.Key("score"); + sb.WriteInt64(row.rating_score); + sb.Key("count"); + sb.WriteInt64(row.rating_count); + } + } + } + } + + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, "application/json"); + return sb.GetString(); +} +} // namespace userver_httparena::async_db diff --git a/frameworks/userver/userver_benchmark/src/handlers/async_db/handler.hpp b/frameworks/userver/userver_benchmark/src/handlers/async_db/handler.hpp new file mode 100644 index 000000000..b4e7358cd --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/async_db/handler.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +namespace userver_httparena::async_db { +class Handler final : public userver::server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "async-db-handler"; + + Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context); + + std::string HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const final; + + private: + const userver::storages::postgres::ClusterPtr pg_; +}; +} // namespace userver_httparena::async_db diff --git a/frameworks/userver/userver_benchmark/src/handlers/baseline11/handler.cpp b/frameworks/userver/userver_benchmark/src/handlers/baseline11/handler.cpp new file mode 100644 index 000000000..87ca1a4a0 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/baseline11/handler.cpp @@ -0,0 +1,35 @@ +#include "handler.hpp" + +#include + +#include + +namespace userver_httparena::baseline11 { +const std::string kContentTypeTextPlain{"text/plain"}; + +std::string Handler::HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const { + const auto& a = request.GetArg("a"); + const auto& b = request.GetArg("b"); + std::string body; + if (request.GetMethod() == userver::server::http::HttpMethod::kPost) { + body = request.RequestBody(); + } + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, kContentTypeTextPlain); + return GetResponse(a, b, body); +} + +std::string Handler::GetResponse(const std::string& a, const std::string& b, const std::string& body) { + int sum = 0; + std::from_chars(a.data(), a.data() + a.size(), sum); + int b_val = 0; + std::from_chars(b.data(), b.data() + b.size(), b_val); + sum += b_val; + if (!body.empty()) { + int body_val = 0; + std::from_chars(body.data(), body.data() + body.size(), body_val); + sum += body_val; + } + return std::to_string(sum); +} +} // namespace userver_httparena::baseline11 diff --git a/frameworks/userver/userver_benchmark/src/handlers/baseline11/handler.hpp b/frameworks/userver/userver_benchmark/src/handlers/baseline11/handler.hpp new file mode 100644 index 000000000..ab965cf85 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/baseline11/handler.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace userver_httparena::baseline11 { +class Handler final : public userver::server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "baseline11-handler"; + + using HttpHandlerBase::HttpHandlerBase; + + std::string HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const final; + + static std::string GetResponse(const std::string& a, const std::string& b, const std::string& body); +}; +} // namespace userver_httparena::baseline11 diff --git a/frameworks/userver/userver_benchmark/src/handlers/baseline2/handler.cpp b/frameworks/userver/userver_benchmark/src/handlers/baseline2/handler.cpp new file mode 100644 index 000000000..31d8e57a1 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/baseline2/handler.cpp @@ -0,0 +1,21 @@ +#include "handler.hpp" + +#include + +#include + +namespace userver_httparena::baseline2 { +std::string Handler::HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const { + const auto& a = request.GetArg("a"); + const auto& b = request.GetArg("b"); + + int sum = 0, b_val = 0; + std::from_chars(a.data(), a.data() + a.size(), sum); + std::from_chars(b.data(), b.data() + b.size(), b_val); + sum += b_val; + + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, "text/plain"); + return std::to_string(sum); +} +} // namespace userver_httparena::baseline2 diff --git a/frameworks/userver/userver_benchmark/src/handlers/baseline2/handler.hpp b/frameworks/userver/userver_benchmark/src/handlers/baseline2/handler.hpp new file mode 100644 index 000000000..1c6b6814d --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/baseline2/handler.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace userver_httparena::baseline2 { +class Handler final : public userver::server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "baseline2-handler"; + + using HttpHandlerBase::HttpHandlerBase; + + std::string HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const final; +}; +} // namespace userver_httparena::baseline2 diff --git a/frameworks/userver/userver_benchmark/src/handlers/json/handler.cpp b/frameworks/userver/userver_benchmark/src/handlers/json/handler.cpp new file mode 100644 index 000000000..2a35321ff --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/json/handler.cpp @@ -0,0 +1,62 @@ +#include "handler.hpp" + +#include +#include + +#include +#include +#include +#include + +#include "dataset_provider.hpp" + +namespace userver_httparena::json { +Handler::Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : HttpHandlerBase(config, context), dataset_provider_{context.FindComponent()} {} + +std::string Handler::HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const { + const auto& count_str = request.GetPathArg("count"); + const auto& m_str = request.GetArg("m"); + + auto count = 0; + std::from_chars(count_str.data(), count_str.data() + count_str.size(), count); + auto m = 1.0; + if (!m_str.empty()) { + std::from_chars(m_str.data(), m_str.data() + m_str.size(), m); + } + + const auto& items = dataset_provider_.GetItems(); + if (count < 0) count = 0; + if (static_cast(count) > items.size()) { + count = static_cast(items.size()); + } + + userver::formats::json::StringBuilder sb; + { + userver::formats::json::StringBuilder::ObjectGuard root_guard(sb); + sb.Key("count"); + sb.WriteInt64(count); + sb.Key("items"); + { + userver::formats::json::StringBuilder::ArrayGuard items_guard(sb); + for (int i = 0; i < count; ++i) { + const auto& item = items[i]; + userver::formats::json::StringBuilder::ObjectGuard item_guard(sb); + sb.Key("id"); + sb.WriteInt64(item.id); + sb.Key("price"); + sb.WriteInt64(item.price); + sb.Key("quantity"); + sb.WriteInt64(item.quantity); + sb.Key("total"); + sb.WriteDouble(static_cast(item.price) * item.quantity * m); + } + } + } + + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, "application/json"); + return sb.GetString(); +} +} // namespace userver_httparena::json diff --git a/frameworks/userver/userver_benchmark/src/handlers/json/handler.hpp b/frameworks/userver/userver_benchmark/src/handlers/json/handler.hpp new file mode 100644 index 000000000..e540f7b04 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/json/handler.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include + +namespace userver_httparena { +class DatasetProvider; + +namespace json { +class Handler final : public userver::server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "json-handler"; + + Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context); + + std::string HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const final; + + private: + const DatasetProvider& dataset_provider_; +}; +} // namespace json +} // namespace userver_httparena diff --git a/frameworks/userver/userver_benchmark/src/handlers/plaintext/handler.cpp b/frameworks/userver/userver_benchmark/src/handlers/plaintext/handler.cpp new file mode 100644 index 000000000..150e249c3 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/plaintext/handler.cpp @@ -0,0 +1,15 @@ +#include "handler.hpp" + +#include + +namespace userver_httparena::plaintext { +const std::string kContentTypeTextPlain{"text/plain"}; + +std::string Handler::HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const { + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, kContentTypeTextPlain); + return GetResponse(); +} + +std::string Handler::GetResponse() { return "ok"; } +} // namespace userver_httparena::plaintext diff --git a/frameworks/userver/userver_benchmark/src/handlers/plaintext/handler.hpp b/frameworks/userver/userver_benchmark/src/handlers/plaintext/handler.hpp new file mode 100644 index 000000000..1a9a26bec --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/plaintext/handler.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace userver_httparena::plaintext { +class Handler final : public userver::server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "plaintext-handler"; + + using HttpHandlerBase::HttpHandlerBase; + + std::string HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const final; + + static std::string GetResponse(); +}; +} // namespace userver_httparena::plaintext diff --git a/frameworks/userver/userver_benchmark/src/handlers/upload/handler.cpp b/frameworks/userver/userver_benchmark/src/handlers/upload/handler.cpp new file mode 100644 index 000000000..d03975d1d --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/upload/handler.cpp @@ -0,0 +1,12 @@ +#include "handler.hpp" + +#include + +namespace userver_httparena::upload { +std::string Handler::HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const { + const auto& body = request.RequestBody(); + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, "text/plain"); + return std::to_string(body.size()); +} +} // namespace userver_httparena::upload diff --git a/frameworks/userver/userver_benchmark/src/handlers/upload/handler.hpp b/frameworks/userver/userver_benchmark/src/handlers/upload/handler.hpp new file mode 100644 index 000000000..d36eb0604 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/handlers/upload/handler.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace userver_httparena::upload { +class Handler final : public userver::server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "upload-handler"; + + using HttpHandlerBase::HttpHandlerBase; + + std::string HandleRequestThrow(const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const final; +}; +} // namespace userver_httparena::upload diff --git a/frameworks/userver/userver_benchmark/src/main.cpp b/frameworks/userver/userver_benchmark/src/main.cpp new file mode 100644 index 000000000..b2bbdfe38 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/main.cpp @@ -0,0 +1,62 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "dataset_provider.hpp" +#include "handlers/async_db/handler.hpp" +#include "handlers/baseline11/handler.hpp" +#include "handlers/baseline2/handler.hpp" +#include "handlers/json/handler.hpp" +#include "handlers/plaintext/handler.hpp" +#include "handlers/upload/handler.hpp" +#include "middlewares/compression.hpp" +#include "middlewares/compression_pipeline_builder.hpp" + +namespace userver_httparena { +class NoopTracingManager final : public userver::tracing::TracingManagerComponentBase { + public: + static constexpr std::string_view kName{"noop-tracing-manager"}; + using userver::tracing::TracingManagerComponentBase::TracingManagerComponentBase; + + protected: + bool TryFillSpanBuilderFromRequest(const userver::server::http::HttpRequest&, + userver::tracing::SpanBuilder&) const final { + return true; + } + + void FillRequestWithTracingContext(const userver::tracing::Span&, + userver::clients::http::MiddlewareRequest) const final {} + + void FillResponseWithTracingContext(const userver::tracing::Span&, userver::server::http::HttpResponse&) const final { + } +}; +} // namespace userver_httparena + +int main(int argc, char* argv[]) { + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append("fs-cache-static") + .Append() + .Append("hello-world-db") + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append >() + .Append() + .Append(); + return userver::utils::DaemonMain(argc, argv, component_list); +} diff --git a/frameworks/userver/userver_benchmark/src/middlewares/compression.cpp b/frameworks/userver/userver_benchmark/src/middlewares/compression.cpp new file mode 100644 index 000000000..1059e1a16 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/middlewares/compression.cpp @@ -0,0 +1,64 @@ +#include "compression.hpp" + +#include + +#include +#include +#include +#include + +namespace userver_httparena::middlewares { +namespace { +bool ShouldCompress(const userver::server::http::HttpRequest& request) { + const auto& accept_encoding = request.GetHeader(userver::http::headers::kAcceptEncoding); + return accept_encoding.find("gzip") != std::string_view::npos; +} + +std::string CompressGzip(std::string_view input) { + z_stream strm = {}; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) { + return std::string{input}; + } + + const auto bound = deflateBound(&strm, input.size()); + std::string output(bound, '\0'); + + strm.next_in = reinterpret_cast(const_cast(input.data())); + strm.avail_in = input.size(); + strm.next_out = reinterpret_cast(output.data()); + strm.avail_out = bound; + + const int ret = deflate(&strm, Z_FINISH); + if (ret != Z_STREAM_END) { + deflateEnd(&strm); + return std::string{input}; + } + + output.resize(strm.total_out); + deflateEnd(&strm); + return output; +} +} // namespace + +CompressionMiddleware::CompressionMiddleware(const userver::server::handlers::HttpHandlerBase&) {} + +void CompressionMiddleware::HandleRequest(userver::server::http::HttpRequest& request, + userver::server::request::RequestContext& context) const { + Next(request, context); + + auto& response = request.GetHttpResponse(); + if (!ShouldCompress(request)) return; + if (response.IsBodyStreamed()) return; + + const auto& body = response.GetData(); + if (body.empty()) return; + + const auto compressed = CompressGzip(body); + response.SetHeader(userver::http::headers::kContentEncoding, "gzip"); + response.SetData(compressed); +} +} // namespace userver_httparena::middlewares diff --git a/frameworks/userver/userver_benchmark/src/middlewares/compression.hpp b/frameworks/userver/userver_benchmark/src/middlewares/compression.hpp new file mode 100644 index 000000000..f3ced11fc --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/middlewares/compression.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include + +namespace userver_httparena::middlewares { +class CompressionMiddleware final : public userver::server::middlewares::HttpMiddlewareBase { + public: + static constexpr std::string_view kName = "compression-middleware"; + + explicit CompressionMiddleware(const userver::server::handlers::HttpHandlerBase&); + + void HandleRequest(userver::server::http::HttpRequest& request, + userver::server::request::RequestContext& context) const final; +}; +} // namespace userver_httparena::middlewares diff --git a/frameworks/userver/userver_benchmark/src/middlewares/compression_pipeline_builder.hpp b/frameworks/userver/userver_benchmark/src/middlewares/compression_pipeline_builder.hpp new file mode 100644 index 000000000..b189f5019 --- /dev/null +++ b/frameworks/userver/userver_benchmark/src/middlewares/compression_pipeline_builder.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "middlewares/compression.hpp" + +namespace userver_httparena::middlewares { +class CompressionPipelineBuilder final : public userver::server::middlewares::HandlerPipelineBuilder { + public: + static constexpr std::string_view kName = "compression-pipeline-builder"; + + using HandlerPipelineBuilder::HandlerPipelineBuilder; + + userver::server::middlewares::MiddlewaresList BuildPipeline( + userver::server::middlewares::MiddlewaresList pipeline) const override { + pipeline.emplace_back(CompressionMiddleware::kName); + return pipeline; + } +}; +} // namespace userver_httparena::middlewares diff --git a/frameworks/userver/userver_benchmark/userver_httparena.cpp b/frameworks/userver/userver_benchmark/userver_httparena.cpp deleted file mode 100644 index fc016e956..000000000 --- a/frameworks/userver/userver_benchmark/userver_httparena.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "controllers/plaintext/handler.hpp" -#include "controllers/baseline11/handler.hpp" -#include "controllers/json/handler.hpp" -#include "controllers/single_query/handler.hpp" - -namespace userver_httparena { - -class NoopTracingManager final - : public userver::tracing::TracingManagerComponentBase { - public: - static constexpr std::string_view kName{"noop-tracing-manager"}; - using userver::tracing::TracingManagerComponentBase:: - TracingManagerComponentBase; - - protected: - bool TryFillSpanBuilderFromRequest( - const userver::server::http::HttpRequest&, - userver::tracing::SpanBuilder&) const final { - return true; - } - - void FillRequestWithTracingContext( - const userver::tracing::Span&, - userver::clients::http::MiddlewareRequest) const final {} - - void FillResponseWithTracingContext( - const userver::tracing::Span&, - userver::server::http::HttpResponse&) const final {} -}; - -int Main(int argc, char* argv[]) -{ - auto component_list = - userver::components::MinimalServerComponentList() - // some required infra - .Append() - .Append() - .Append() - .Append() - .Append("fs-cache-static") - .Append() - .Append("hello-world-db") - // actual handlers - .Append() - .Append() - .Append() - .Append() - // tracing tweaks - .Append() - ; - return userver::utils::DaemonMain(argc, argv, component_list); -} - -} // namespace userver_httparena - -int main(int argc, char* argv[]) { - return userver_httparena::Main(argc, argv); -} diff --git a/frameworks/userver/userver_configs/dynamic_config_fallback.json b/frameworks/userver/userver_configs/dynamic_config_fallback.json deleted file mode 100644 index 2929532e8..000000000 --- a/frameworks/userver/userver_configs/dynamic_config_fallback.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "USERVER_CACHES": {}, - "USERVER_CANCEL_HANDLE_REQUEST_BY_DEADLINE": false, - "POSTGRES_CONGESTION_CONTROL_SETTINGS": {}, - "POSTGRES_DEADLINE_PROPAGATION_VERSION": 0, - "POSTGRES_CONNECTION_PIPELINE_EXPERIMENT": 5, - "USERVER_CHECK_AUTH_IN_HANDLERS": false, - "USERVER_DUMPS": {}, - "USERVER_HTTP_PROXY": "", - "USERVER_LOG_REQUEST": false, - "USERVER_LOG_REQUEST_HEADERS": false, - "USERVER_LRU_CACHES": {}, - "USERVER_RPS_CCONTROL_CUSTOM_STATUS": {}, - "USERVER_TASK_PROCESSOR_PROFILER_DEBUG": {}, - "USERVER_HANDLER_STREAM_API_ENABLED": false, - "HTTP_CLIENT_CONNECTION_POOL_SIZE": 1000, - "HTTP_CLIENT_CONNECT_THROTTLE": { - "http-limit": 6000, - "http-per-second": 1500, - "https-limit": 100, - "https-per-second": 25, - "per-host-limit": 3000, - "per-host-per-second": 500 - }, - "HTTP_CLIENT_ENFORCE_TASK_DEADLINE": { - "cancel-request": false, - "update-timeout": false - }, - "BAGGAGE_SETTINGS": { - "allowed_keys": [] - }, - "USERVER_BAGGAGE_ENABLED": false, - "USERVER_TASK_PROCESSOR_QOS": { - "default-service": { - "default-task-processor": { - "wait_queue_overload": { - "action": "ignore", - "length_limit": 0, - "time_limit_us": 10000000 - } - } - } - }, - - "POSTGRES_STATEMENT_METRICS_SETTINGS": {}, - "POSTGRES_CONNLIMIT_MODE_AUTO_ENABLED": false, - "USERVER_DEADLINE_PROPAGATION_ENABLED": false, - "POSTGRES_CONNECTION_POOL_SETTINGS": {}, - "POSTGRES_CONNECTION_SETTINGS": {}, - "POSTGRES_DEFAULT_COMMAND_CONTROL": { - "network_timeout_ms": 7000, - "statement_timeout_ms": 7000 - }, - "POSTGRES_HANDLERS_COMMAND_CONTROL": {}, - "POSTGRES_QUERIES_COMMAND_CONTROL": {} -} diff --git a/frameworks/userver/userver_configs/secure_data.json b/frameworks/userver/userver_configs/secure_data.json deleted file mode 100644 index 62c59bb1e..000000000 --- a/frameworks/userver/userver_configs/secure_data.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "postgresql_settings": { - "databases": { - "hello_world": [{ - "shard_number" : 0, - "hosts": [ - "postgresql://bench:bench@localhost:5432/benchmark?sslmode=disable" - ] - }] - } - } -}